// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ------------------------------------------------------------------
// Modification history:
// feature: support agent between domain
// feature: Unified Transport Abstraction Layer Unified Transport Abstraction Layer
// feature: implement IPC transport
// feature: another method of counting packet lost
// feature: add api consumer
// feature: QoS Profile Inheritance and Composition
// feature: use xml to set log level
// feature: Change the default order and test domain sope
// feature: log namespace change
// feature: simplify xml profile
// feature: FileConsumer::maxSize_ is modified to be in K bytes
// feature: compatible with DSF
// feature: flowcontroller xml config and writer/reader-resourcelimit
// ------------------------------------------------------------------

#include <ertps/xmlparser/XMLParser.h>

#include <xmlparser/XMLTreePart.h>

#include <transport/UDPv4TransportDescriptor.h>
#ifdef EDDS_TCP_TRANSPORT_COMPILE
#include <transport/TCPv4TransportDescriptor.h>
#endif
#ifdef VBS_IPV6
#include <transport/UDPv6TransportDescriptor.h>
#include <transport/TCPv6TransportDescriptor.h>
#endif
#include <transport/SharedMemTransportDescriptor.h>
#include <transport/IPCTransportDescriptor.h>

#include <ertps/xmlparser/XMLProfileManager.h>

#include <elog/FileConsumer.hpp>
#include <elog/StdoutConsumer.hpp>
#include <elog/StdoutErrConsumer.hpp>
#ifndef UNITEST_STATISTICS
// #include <edds/dds/log_online/OnlineLogPublisher.h>
// #include <edds/dds/log_online/OnlineConsumer.hpp>
#endif

#include <tinyxml2.h>

#include <cstdlib>
#include <iostream>
#include <string>
#include <unordered_map>

#include <xmlparser/XMLParserPart.h>

namespace evbs {
namespace ertps {
namespace xmlparser {

std::set<std::string> XMLParser::agent_allowed_topic_;
std::mutex XMLParser::mutex_;

XMLP_ret XMLParser::parseXML(tinyxml2::XMLDocument& xmlDoc, vbsutil::xmlparser::up_base_node_t& root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* node = xmlDoc.FirstChildElement();
    if ((node == nullptr) || (node->Value() == nullptr)) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "xml config is empty.");
        return XMLP_ret::XML_ERROR;
    }

    const char* vbs_tag = node->Value();
    if (strcmp(vbs_tag, xmlString::VBS) == 0) {
        node = node->FirstChildElement();
        if (strcmp(node->Value(), xmlString::RPC) == 0) {
            node = node->NextSiblingElement();
        }
    }

    const char* root_tag = node->Value();
    if (strcmp(root_tag, xmlString::DDS) == 0) {
        node = node->FirstChildElement();
    }
    const char* tag = nullptr;
    while ((node != nullptr) && (ret == XMLP_ret::XML_OK)) {
        if ((tag = node->Value()) != nullptr) {
            if (strcmp(tag, xmlString::PROFILES) == 0) {
                ret = parseProfiles(node);
            } else if (strcmp(tag, xmlString::TYPES) == 0) {
                vbsutil::xmlparser::up_base_node_t types_node = vbsutil::xmlparser::up_base_node_t {
                    new vbsutil::xmlparser::BaseNode {vbsutil::xmlparser::NodeType::TYPES}};
                if (XMLP_ret::XML_OK == (ret = parseXMLTypes(node))) {
                    root->addChild(std::move(types_node));
                }
            } else if (strcmp(tag, xmlString::LOG) == 0) {
                ret = parseLogConfig(node);
            } else if (strcmp(tag, xmlString::LIBRARY_SETTINGS) == 0) {
                vbsutil::xmlparser::up_base_node_t library_node = vbsutil::xmlparser::up_base_node_t {
                    new vbsutil::xmlparser::BaseNode {vbsutil::xmlparser::NodeType::LIBRARY_SETTINGS}};
                if (XMLP_ret::XML_OK == (ret = parseXMLLibrarySettings(node))) {
                    root->addChild(std::move(library_node));
                }
            } else if (strcmp(tag, xmlString::BASEXML) == 0 || strcmp(tag, xmlString::RPC) == 0) {
            } else if (strcmp(tag, xmlString::AGENT) == 0) {
                ret = parseAgentConfig(node);
#if HAVE_SECURITY
            } else if (strcmp(tag, xmlString::SECURITY) == 0) {
                const char* text = node->GetText();
                if (text != nullptr) {
                    std::string security;
                    security.resize(strlen(text));
                    // convert to lowercase
                    std::transform(text, text + security.size(), security.begin(),
                                   [](unsigned char c) { return std::tolower(c); });

                    if (security == "false") {
                        vbsutil::xmlparser::XMLParserpart::set_security(false);
                    } else if (security == "true") {
                        vbsutil::xmlparser::XMLParserpart::set_security(true);
                    } else if (security == "enforcing") {
                        vbsutil::xmlparser::XMLParserpart::set_enforce(true);
                    } else if (security == "permissive") {
                        vbsutil::xmlparser::XMLParserpart::set_enforce(false);
                    }
                }
#endif
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not expected tag: '" << tag << "'");
                ret = XMLP_ret::XML_ERROR;
            }
        }
        node = node->NextSiblingElement();
    }
    return ret;
}

XMLP_ret XMLParser::parseXMLProfiles(tinyxml2::XMLElement& profiles, vbsutil::xmlparser::up_base_node_t& root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    root.reset(new vbsutil::xmlparser::BaseNode {vbsutil::xmlparser::NodeType::PROFILES});
    // 先调用xml独立库解析，再解析evbs中需要解析的模块
    if (vbsutil::xmlparser::XMLParserpart::parseProfiles(&profiles, *root) != XMLP_ret::XML_OK) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "parseProfiles  xmlpart Error");
        return XMLP_ret::XML_ERROR;
    }
    ret = parseProfiles(&profiles);
    return ret;
}

XMLP_ret XMLParser::parseXMLTransportsProf(tinyxml2::XMLElement* p_root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_element = p_root->FirstChildElement(xmlString::TRANSPORT_DESCRIPTOR);
    while (p_element != nullptr) {
        ret = parseXMLTransportData(p_element);
        if (ret != XMLP_ret::XML_OK) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing transports");
            return ret;
        }
        p_element = p_element->NextSiblingElement(xmlString::TRANSPORT_DESCRIPTOR);
    }
    return ret;
}

XMLP_ret XMLParser::parseXMLTransportData(tinyxml2::XMLElement* p_root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    std::string sId = "";
    sp_transport_t pDescriptor = nullptr;

    tinyxml2::XMLElement* p_aux0 = nullptr;
    p_aux0 = p_root->FirstChildElement(xmlString::TRANSPORT_ID);
    if (nullptr == p_aux0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not found '" << xmlString::TRANSPORT_ID << "' attribute");
        return XMLP_ret::XML_ERROR;
    } else {
        if (p_aux0->GetText() != nullptr) {
            sId = p_aux0->GetText();
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "'" << xmlString::TRANSPORT_ID << "' attribute cannot be empty");
            return XMLP_ret::XML_ERROR;
        }
        XMLProfileManager::userTransportsId.push_back(sId);  // 保存模板中的所有tranportid数据
    }

    p_aux0 = p_root->FirstChildElement(xmlString::TYPE);
    if (nullptr == p_aux0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not found '" << xmlString::TYPE << "' attribute");
        return XMLP_ret::XML_ERROR;
    } else {
        std::string sType;
        if (p_aux0->GetText() != nullptr) {
            sType = p_aux0->GetText();
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "'" << xmlString::TYPE << "' attribute cannot be empty");
            return XMLP_ret::XML_ERROR;
        }

        if ((sType == xmlString::UDPv4) || (sType == xmlString::UDPv6)) {
            if (sType == xmlString::UDPv4) {
                pDescriptor = std::make_shared<vbs::transport::UDPv4TransportDescriptor>();
#ifdef VBS_IPV6
            } else {
                pDescriptor = std::make_shared<vbs::transport::UDPv6TransportDescriptor>();
#endif
            }

            std::shared_ptr<vbs::transport::UDPTransportDescriptor> pUDPDesc =
                std::dynamic_pointer_cast<vbs::transport::UDPTransportDescriptor>(pDescriptor);
            if (nullptr == pUDPDesc) {
                return XMLP_ret::XML_ERROR;
            }
            // Output UDP Socket
            if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::UDP_OUTPUT_PORT))) {
                int iSocket = 0;
                if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iSocket, 0)) ||
                    (iSocket < 0) || (iSocket > 65535)) {
                    return XMLP_ret::XML_ERROR;
                }
                pUDPDesc->m_output_udp_socket = static_cast<uint16_t>(iSocket);
            }
            // Non-blocking send
            if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::NON_BLOCKING_SEND))) {
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLBool(p_aux0, &pUDPDesc->non_blocking_send, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            }
#ifdef EDDS_XDP_TRANSPORT_COMPILE
            // Socket type
            if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::UDP_SOCKET_TYPE))) {
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pUDPDesc->socket_type_, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            }
            if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::XDP_RX_QUEUE_NUM))) {
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &pUDPDesc->xdp_rx_queue_num, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            }
#endif
        }
#ifdef EDDS_TCP_TRANSPORT_COMPILE
        else if (sType == xmlString::TCPv4) {
            pDescriptor = std::make_shared<vbs::transport::TCPv4TransportDescriptor>();
            ret = parseXMLCommonTCPTransportData(p_root, pDescriptor);
            if (ret != XMLP_ret::XML_OK) {
                return ret;
            } else {
                std::shared_ptr<vbs::transport::TCPv4TransportDescriptor> pTCPv4Desc =
                    std::dynamic_pointer_cast<vbs::transport::TCPv4TransportDescriptor>(pDescriptor);

                // Wan Address
                if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::TCP_WAN_ADDR))) {
                    std::string s;
                    if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &s, 0U)) {
                        return XMLP_ret::XML_ERROR;
                    }
                    pTCPv4Desc->set_WAN_address(s);
                }
            }
        }
#endif
#ifdef EDDS_SHM_TRANSPORT_COMPILE
        else if (sType == xmlString::SHM) {
            pDescriptor = std::make_shared<vbs::transport::SharedMemTransportDescriptor>();
            ret = parseXMLCommonSharedMemTransportData(p_root, pDescriptor);
            if (ret != XMLP_ret::XML_OK) {
                return ret;
            }
        }
#endif
#ifdef EDDS_IPC_TRANSPORT
        else if (sType == xmlString::IPC) {
            pDescriptor = std::make_shared<vbs::transport::IPCTransportDescriptor>();
            if (nullptr != (p_aux0 = p_root->FirstChildElement(xmlString::MAX_MESSAGE_SIZE))) {
                uint32_t uSize = 0U;

                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &uSize, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                pDescriptor->maxMessageSize = uSize;
            }
        }
#endif
        else if (sType == xmlString::SHARED_SHM_QUEUE) {
            logWarning(XMLPARSER, "Invalid transport type: '" << sType << "', skip");
            return XMLP_ret::XML_OK;
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Invalid transport type: '" << sType << "'");
            return XMLP_ret::XML_ERROR;
        }

        if (sType != xmlString::SHM
#ifdef EDDS_IPC_TRANSPORT
            && sType != xmlString::IPC
#endif
        ) {
            ret = parseXMLCommonTransportData(p_root, pDescriptor);
            if (ret != XMLP_ret::XML_OK) {
                return ret;
            }
        }

        (void)XMLProfileManager::insertTransportById(sId, std::move(pDescriptor));
    }
    return ret;
}

XMLP_ret XMLParser::parseXMLCommonTransportData(tinyxml2::XMLElement* p_root, sp_transport_t p_transport) {
    std::shared_ptr<vbs::transport::SocketTransportDescriptor> pDesc =
        std::dynamic_pointer_cast<vbs::transport::SocketTransportDescriptor>(p_transport);

    tinyxml2::XMLElement* p_aux0 = nullptr;
    const char* name = nullptr;
    for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) {
        name = p_aux0->Name();
        if (strcmp(name, xmlString::SEND_BUFFER_SIZE) == 0) {
            // sendBufferSize - int32Type
            uint32_t iSize = 0U;
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &iSize, 0U)) {
                return XMLP_ret::XML_ERROR;
            }
            pDesc->sendBufferSize = iSize;
        } else if (strcmp(name, xmlString::RECEIVE_BUFFER_SIZE) == 0) {
            // receiveBufferSize - int32Type
            uint32_t iSize = 0U;
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &iSize, 0U)) {
                return XMLP_ret::XML_ERROR;
            }
            pDesc->receiveBufferSize = iSize;
        } else if (strcmp(name, xmlString::TTL) == 0) {
            // TTL - int8Type
            int iTTL = 0;
            if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iTTL, 0)) || (iTTL < 0) ||
                (iTTL > 255)) {
                return XMLP_ret::XML_ERROR;
            }
            pDesc->TTL = static_cast<uint8_t>(iTTL);
        } else if (strcmp(name, xmlString::MAX_MESSAGE_SIZE) == 0) {
            // maxMessageSize - uint32Type
            uint32_t uSize = 0U;
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &uSize, 0)) {
                return XMLP_ret::XML_ERROR;
            }
            std::dynamic_pointer_cast<vbs::transport::TransportDescriptorInterface>(p_transport)->maxMessageSize =
                uSize;
        } else if (strcmp(name, xmlString::MAX_INITIAL_PEERS_RANGE) == 0) {
            // maxInitialPeersRange - uint32Type
            uint32_t uRange = 0U;
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &uRange, 0)) {
                return XMLP_ret::XML_ERROR;
            }
            pDesc->maxInitialPeersRange = uRange;
        } else if (strcmp(name, xmlString::WHITE_LIST) == 0) {
            // InterfaceWhiteList addressListType
            const char* address = nullptr;
            for (tinyxml2::XMLElement* p_aux1 = p_aux0->FirstChildElement(); p_aux1 != nullptr;
                 p_aux1 = p_aux1->NextSiblingElement()) {
                address = p_aux1->Name();
                if (strcmp(address, xmlString::ADDRESS) == 0) {
                    const char* text = p_aux1->GetText();
                    if (nullptr != text) {
                        vbsutil::xmlparser::WhiteListAddr w_addr = {text, 65535};
                        pDesc->interfaceWhiteList.emplace_back(w_addr);
                    }
                } else if (strcmp(address, xmlString::WHITE_LIST_ADDRESS) == 0) {
                    vbsutil::xmlparser::WhiteListAddr w_addr = {"", 65535};
                    for (tinyxml2::XMLElement* p_aux2 = p_aux1->FirstChildElement(); p_aux2 != nullptr;
                         p_aux2 = p_aux2->NextSiblingElement()) {
                        address = p_aux2->Name();
                        if (strcmp(address, xmlString::ADDRESS) == 0) {
                            const char* text = p_aux2->GetText();
                            if (nullptr != text) {
                                w_addr.addr = text;
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "'whiteListAddress'. address: nullptr ");
                                return XMLP_ret::XML_ERROR;
                            }
                        } else if (strcmp(address, xmlString::ORDER) == 0) {
                            if (XMLP_ret::XML_OK !=
                                vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux2, &w_addr.order, 0)) {
                                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "'whiteListAddress'. order get error ");
                                return XMLP_ret::XML_ERROR;
                            }
                            if (w_addr.order == 0 || w_addr.order >= 65536) {
                                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                                          "'whiteListAddress'. order must be greater than 0 and less than 65536.");
                                return XMLP_ret::XML_ERROR;
                            }
                        }
                    }
                    pDesc->interfaceWhiteList.emplace_back(w_addr);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "Invalid element found into 'interfaceWhiteList'. Name: " << address);
                    return XMLP_ret::XML_ERROR;
                }
            }
        } else if ((strcmp(name, xmlString::TCP_WAN_ADDR) == 0) || (strcmp(name, xmlString::UDP_OUTPUT_PORT) == 0) ||
                   (strcmp(name, xmlString::TRANSPORT_ID) == 0) || (strcmp(name, xmlString::TYPE) == 0) ||
                   (strcmp(name, xmlString::KEEP_ALIVE_FREQUENCY) == 0) ||
                   (strcmp(name, xmlString::KEEP_ALIVE_TIMEOUT) == 0) ||
                   (strcmp(name, xmlString::MAX_LOGICAL_PORT) == 0) ||
                   (strcmp(name, xmlString::LOGICAL_PORT_RANGE) == 0) ||
                   (strcmp(name, xmlString::LOGICAL_PORT_INCREMENT) == 0) ||
                   (strcmp(name, xmlString::LISTENING_PORTS) == 0) || (strcmp(name, xmlString::CALCULATE_CRC) == 0) ||
                   (strcmp(name, xmlString::CHECK_CRC) == 0) || (strcmp(name, xmlString::ENABLE_TCP_NODELAY) == 0) ||
                   (strcmp(name, xmlString::TLS) == 0) || (strcmp(name, xmlString::NON_BLOCKING_SEND) == 0) ||
                   (strcmp(name, xmlString::SEGMENT_SIZE) == 0) ||
                   (strcmp(name, xmlString::PORT_QUEUE_CAPACITY) == 0) ||
                   (strcmp(name, xmlString::PORT_OVERFLOW_POLICY) == 0) ||
                   (strcmp(name, xmlString::SEGMENT_OVERFLOW_POLICY) == 0) ||
                   (strcmp(name, xmlString::HEALTHY_CHECK_TIMEOUT_MS) == 0) ||
                   (strcmp(name, xmlString::HEALTHY_CHECK_TIMEOUT_MS) == 0) ||
                   (strcmp(name, xmlString::RTPS_DUMP_FILE) == 0)
#ifdef EDDS_XDP_TRANSPORT_COMPILE
                   || (strcmp(name, xmlString::UDP_SOCKET_TYPE) == 0)
#endif
        ) {
            // Parsed outside of this method
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "Invalid element found into 'rtpsTransportDescriptorType'. Name: " << name);
            return XMLP_ret::XML_ERROR;
        }
    }
    return XMLP_ret::XML_OK;
}

#ifdef EDDS_TCP_TRANSPORT_COMPILE
XMLP_ret XMLParser::parseXMLCommonTCPTransportData(tinyxml2::XMLElement* p_root, sp_transport_t p_transport) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    std::shared_ptr<vbs::transport::TCPTransportDescriptor> pTCPDesc =
        std::dynamic_pointer_cast<vbs::transport::TCPTransportDescriptor>(p_transport);
    if (pTCPDesc != nullptr) {
        tinyxml2::XMLElement* p_aux0 = nullptr;
        const char* name = nullptr;
        for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) {
            name = p_aux0->Name();
            if (strcmp(name, xmlString::KEEP_ALIVE_FREQUENCY) == 0) {
                // keep_alive_frequency_ms - uint32Type
                int iFrequency(0);
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iFrequency, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
                pTCPDesc->keep_alive_frequency_ms = static_cast<uint32_t>(iFrequency);
            } else if (strcmp(name, xmlString::KEEP_ALIVE_TIMEOUT) == 0) {
                // keep_alive_timeout_ms - uint32Type
                int iTimeout(0);
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iTimeout, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
                pTCPDesc->keep_alive_timeout_ms = static_cast<uint32_t>(iTimeout);
            } else if (strcmp(name, xmlString::MAX_LOGICAL_PORT) == 0) {
                // max_logical_port - uint16Type
                int iPort(0);
                if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iPort, 0U)) ||
                    (iPort < 0) || (iPort > 65535)) {
                    return XMLP_ret::XML_ERROR;
                }
                pTCPDesc->max_logical_port = static_cast<uint16_t>(iPort);
            } else if (strcmp(name, xmlString::LOGICAL_PORT_RANGE) == 0) {
                // logical_port_range - uint16Type
                int iPort(0);
                if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iPort, 0U)) ||
                    (iPort < 0) || (iPort > 65535)) {
                    return XMLP_ret::XML_ERROR;
                }
                pTCPDesc->logical_port_range = static_cast<uint16_t>(iPort);
            } else if (strcmp(name, xmlString::LOGICAL_PORT_INCREMENT) == 0) {
                // logical_port_increment - uint16Type
                int iPort(0);
                if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &iPort, 0U)) ||
                    (iPort < 0) || (iPort > 65535)) {
                    return XMLP_ret::XML_ERROR;
                }
                pTCPDesc->logical_port_increment = static_cast<uint16_t>(iPort);
            } else if (strcmp(name, xmlString::ENABLE_TCP_NODELAY) == 0) {
                // enable_tcp_nodelay - boolType
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLBool(p_aux0, &pTCPDesc->enable_tcp_nodelay, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(name, xmlString::LISTENING_PORTS) == 0) {
                // listening_ports uint16ListType
                tinyxml2::XMLElement* p_aux1 = p_aux0->FirstChildElement(PORT);
                while (nullptr != p_aux1) {
                    int iPort = 0;
                    if ((XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux1, &iPort, 0U)) ||
                        (iPort < 0) || (iPort > 65535)) {
                        return XMLP_ret::XML_ERROR;
                    }

                    pTCPDesc->add_listener_port(static_cast<uint16_t>(iPort));
                    p_aux1 = p_aux1->NextSiblingElement(PORT);
                }
            } else if (strcmp(name, xmlString::CALCULATE_CRC) == 0) {
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLBool(p_aux0, &pTCPDesc->calculate_crc, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(name, xmlString::CHECK_CRC) == 0) {
                if (XMLP_ret::XML_OK !=
                    vbsutil::xmlparser::XMLParserpart::getXMLBool(p_aux0, &pTCPDesc->check_crc, 0U)) {
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(name, xmlString::TLS) == 0) {
                if (XMLP_ret::XML_OK != parse_tls_config(p_aux0, p_transport)) {
                    return XMLP_ret::XML_ERROR;
                }
            } else if ((strcmp(name, xmlString::TCP_WAN_ADDR) == 0) || (strcmp(name, xmlString::TRANSPORT_ID) == 0) ||
                       (strcmp(name, xmlString::TYPE) == 0) || (strcmp(name, xmlString::SEND_BUFFER_SIZE) == 0) ||
                       (strcmp(name, xmlString::RECEIVE_BUFFER_SIZE) == 0) || (strcmp(name, xmlString::TTL) == 0) ||
                       (strcmp(name, xmlString::MAX_MESSAGE_SIZE) == 0) ||
                       (strcmp(name, xmlString::MAX_INITIAL_PEERS_RANGE) == 0) ||
                       (strcmp(name, xmlString::WHITE_LIST) == 0)) {
                // Parsed Outside of this method
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                          "Invalid element found into 'rtpsTransportDescriptorType'. Name: " << name);
                return XMLP_ret::XML_ERROR;
            }
        }
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing TCP Transport data");
        ret = XMLP_ret::XML_ERROR;
    }

    return ret;
}
#endif

#ifdef EDDS_SHM_TRANSPORT_COMPILE
XMLP_ret XMLParser::parseXMLCommonSharedMemTransportData(tinyxml2::XMLElement* p_root, sp_transport_t p_transport) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    std::shared_ptr<vbs::transports::SharedMemTransportDescriptor> transport_descriptor =
        std::dynamic_pointer_cast<vbs::transport::SharedMemTransportDescriptor>(p_transport);
    if (transport_descriptor != nullptr) {
        tinyxml2::XMLElement* p_aux0 = nullptr;
        const char* name = nullptr;
        for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) {
            uint32_t aux;
            name = p_aux0->Name();
            if (strcmp(name, xmlString::SEGMENT_SIZE) == 0) {
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &aux, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->segment_size(static_cast<uint32_t>(aux));
            } else if (strcmp(name, xmlString::PORT_QUEUE_CAPACITY) == 0) {
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &aux, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->port_queue_capacity(static_cast<uint32_t>(aux));
            } else if (strcmp(name, xmlString::HEALTHY_CHECK_TIMEOUT_MS) == 0) {
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &aux, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->healthy_check_timeout_ms(static_cast<uint32_t>(aux));
            } else if (strcmp(name, xmlString::RTPS_DUMP_FILE) == 0) {
                std::string str;
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &str, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->rtps_dump_file(str);
            } else if (strcmp(name, xmlString::MAX_MESSAGE_SIZE) == 0) {
                // maxMessageSize - uint32Type
                uint32_t uSize = 0;
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &uSize, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->max_message_size(uSize);
            } else if (strcmp(name, xmlString::MAX_INITIAL_PEERS_RANGE) == 0) {
                // maxInitialPeersRange - uint32Type
                uint32_t uRange = 0;
                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_aux0, &uRange, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                transport_descriptor->maxInitialPeersRange = uRange;
            } else if ((strcmp(name, xmlString::TRANSPORT_ID) == 0) || (strcmp(name, TYPE) == 0)) {
                // Parsed Outside of this method
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                          "Invalid element found into 'rtpsTransportDescriptorType'. Name: " << name);
                return XMLP_ret::XML_ERROR;
            }
        }
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing SharedMem Transport data");
        ret = XMLP_ret::XML_ERROR;
    }

    return ret;
}
#endif

#ifdef EDDS_TCP_TRANSPORT_COMPILE
XMLP_ret XMLParser::parse_tls_config(tinyxml2::XMLElement* p_root, sp_transport_t tcp_transport) {
    // using namespace rtps;
    using vbs::transport::TCPTransportDescriptor;
    using TCPDescriptor = std::shared_ptr<vbs::transport::TCPTransportDescriptor>;
    using TLSVerifyMode = TCPTransportDescriptor::TLSConfig::TLSVerifyMode;
    using TLSOption = TCPTransportDescriptor::TLSConfig::TLSOptions;
    using TLSHandShakeMode = TCPTransportDescriptor::TLSConfig::TLSHandShakeRole;

    XMLP_ret ret = XMLP_ret::XML_OK;

    TCPDescriptor pTCPDesc = std::dynamic_pointer_cast<vbs::transport::TCPTransportDescriptor>(tcp_transport);
    pTCPDesc->apply_security = true;

    tinyxml2::XMLElement* p_aux0 = nullptr;

    for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) {
        const std::string config = p_aux0->Value();
        if (config.compare(xmlString::TLS_PASSWORD) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.password, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_PRIVATE_KEY_FILE) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.private_key_file, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_CERT_CHAIN_FILE) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.cert_chain_file, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_TMP_DH_FILE) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.tmp_dh_file, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_VERIFY_FILE) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.verify_file, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_VERIFY_PATHS) == 0) {
            tinyxml2::XMLElement* p_path = p_aux0->FirstChildElement();

            while (p_path != nullptr) {
                std::string type = p_path->Value();
                if (type.compare(xmlString::TLS_VERIFY_PATH) == 0) {
                    std::string path;

                    if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(p_path, &path, 0U)) {
                        ret = XMLP_ret::XML_ERROR;
                    } else {
                        pTCPDesc->tls_config.verify_paths.push_back(path);
                    }

                    if (ret == XMLP_ret::XML_ERROR) {
                        // Break while loop
                        break;
                    }
                    p_path = p_path->NextSiblingElement();
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "Unrecognized verify paths label: " << p_path->Value());
                    ret = XMLP_ret::XML_ERROR;
                    break;
                }
            }
        } else if (config.compare(xmlString::TLS_VERIFY_DEPTH) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLInt(p_aux0, &pTCPDesc->tls_config.verify_depth, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_DEFAULT_VERIFY_PATH) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLBool(p_aux0, &pTCPDesc->tls_config.default_verify_path, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_RSA_PRIVATE_KEY_FILE) == 0) {
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(
                                        p_aux0, &pTCPDesc->tls_config.rsa_private_key_file, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_HANDSHAKE_ROLE) == 0) {
            std::string handshake_mode;
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &handshake_mode, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            } else {
                if (handshake_mode.compare(xmlString::TLS_HANDSHAKE_ROLE_DEFAULT) == 0) {
                    pTCPDesc->tls_config.handshake_role = TLSHandShakeMode::DEFAULT;
                } else if (handshake_mode.compare(xmlString::TLS_HANDSHAKE_ROLE_SERVER) == 0) {
                    pTCPDesc->tls_config.handshake_role = TLSHandShakeMode::SERVER;
                } else if (handshake_mode.compare(xmlString::TLS_HANDSHAKE_ROLE_CLIENT) == 0) {
                    pTCPDesc->tls_config.handshake_role = TLSHandShakeMode::CLIENT;
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "Error parsing TLS configuration handshake_mode unrecognized " << handshake_mode << ".");
                    ret = XMLP_ret::XML_ERROR;
                }
            }
        } else if (config.compare(xmlString::TLS_SERVER_NAME) == 0) {
            if (XMLP_ret::XML_OK !=
                vbsutil::xmlparser::XMLParserpart::getXMLString(p_aux0, &pTCPDesc->tls_config.server_name, 0U)) {
                ret = XMLP_ret::XML_ERROR;
            }
        } else if (config.compare(xmlString::TLS_VERIFY_MODE) == 0) {
            tinyxml2::XMLElement* p_verify = p_aux0->FirstChildElement();
            while (p_verify != nullptr) {
                std::string type = p_verify->Value();
                if (type.compare(xmlString::TLS_VERIFY) == 0) {
                    std::string verify_mode;

                    if (XMLP_ret::XML_OK !=
                        vbsutil::xmlparser::XMLParserpart::getXMLString(p_verify, &verify_mode, 0U)) {
                        ret = XMLP_ret::XML_ERROR;
                    } else {
                        if (verify_mode.compare(xmlString::TLS_VERIFY_NONE) == 0) {
                            pTCPDesc->tls_config.add_verify_mode(TLSVerifyMode::VERIFY_NONE);
                        } else if (verify_mode.compare(xmlString::TLS_VERIFY_PEER) == 0) {
                            pTCPDesc->tls_config.add_verify_mode(TLSVerifyMode::VERIFY_PEER);
                        } else if (verify_mode.compare(xmlString::TLS_VERIFY_FAIL_IF_NO_PEER_CERT) == 0) {
                            pTCPDesc->tls_config.add_verify_mode(TLSVerifyMode::VERIFY_FAIL_IF_NO_PEER_CERT);
                        } else if (verify_mode.compare(xmlString::TLS_VERIFY_CLIENT_ONCE) == 0) {
                            pTCPDesc->tls_config.add_verify_mode(TLSVerifyMode::VERIFY_CLIENT_ONCE);
                        } else {
                            elogError(
                                XMLPARSER, RetCode_t::RETCODE_ERROR,
                                "Error parsing TLS configuration verify_mode unrecognized " << verify_mode << ".");
                            ret = XMLP_ret::XML_ERROR;
                        }
                    }
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "Error parsing TLS configuration found unrecognized node " << type << ".");
                    ret = XMLP_ret::XML_ERROR;
                }

                if (ret == XMLP_ret::XML_ERROR) {
                    // Break while loop
                    break;
                }

                p_verify = p_verify->NextSiblingElement();
            }
        } else if (config.compare(xmlString::TLS_OPTIONS) == 0) {
            tinyxml2::XMLElement* p_option = p_aux0->FirstChildElement();
            while (p_option != nullptr) {
                std::string type = p_option->Value();
                if (type.compare(xmlString::TLS_OPTION) == 0) {
                    std::string option;

                    if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLString(p_option, &option, 0U)) {
                        ret = XMLP_ret::XML_ERROR;
                    } else {
                        if (option.compare(xmlString::TLS_DEFAULT_WORKAROUNDS) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::DEFAULT_WORKAROUNDS);
                        } else if (option.compare(xmlString::TLS_NO_COMPRESSION) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_COMPRESSION);
                        } else if (option.compare(xmlString::TLS_NO_SSLV2) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_SSLV2);
                        } else if (option.compare(xmlString::TLS_NO_SSLV3) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_SSLV3);
                        } else if (option.compare(xmlString::TLS_NO_TLSV1) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_TLSV1);
                        } else if (option.compare(xmlString::TLS_NO_TLSV1_1) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_TLSV1_1);
                        } else if (option.compare(xmlString::TLS_NO_TLSV1_2) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_TLSV1_2);
                        } else if (option.compare(xmlString::TLS_NO_TLSV1_3) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::NO_TLSV1_3);
                        } else if (option.compare(xmlString::TLS_SINGLE_DH_USE) == 0) {
                            pTCPDesc->tls_config.add_option(TLSOption::SINGLE_DH_USE);
                        } else {
                            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                                      "Error parsing TLS configuration option unrecognized " << option << ".");
                            ret = XMLP_ret::XML_ERROR;
                        }
                    }
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "Error parsing TLS options found unrecognized node " << type << ".");
                    ret = XMLP_ret::XML_ERROR;
                }

                if (ret == XMLP_ret::XML_ERROR) {
                    // Break while loop
                    break;
                }

                p_option = p_option->NextSiblingElement();
            }
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "Error parsing TLS configuration: Field " << config << " not recognized.");
            ret = XMLP_ret::XML_ERROR;
        }

        // Stop parsing on error
        if (ret == XMLP_ret::XML_ERROR) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "Error parsing TLS configuration's field '" << config << "'.");
            break;
        }
    }

    return ret;
}
#endif

XMLP_ret XMLParser::parseXMLLibrarySettings(tinyxml2::XMLElement* p_root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    std::string sId = "";

    uint8_t ident = 1U;
    tinyxml2::XMLElement* p_aux0 = nullptr;
    p_aux0 = p_root->FirstChildElement(xmlString::INTRAPROCESS_DELIVERY);
    if (nullptr == p_aux0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                  "Not found '" << xmlString::INTRAPROCESS_DELIVERY << "' attribute");
        return XMLP_ret::XML_ERROR;
    } else {
        LibrarySettingsAttributes library_settings;
        if (XMLP_ret::XML_OK != getXMLEnum(p_aux0, &library_settings.intraprocess_delivery, ident)) {
            return XMLP_ret::XML_ERROR;
        }

        XMLProfileManager::library_settings(library_settings);
    }

    return ret;
}

XMLP_ret XMLParser::parseProfiles(tinyxml2::XMLElement* p_root) {
    tinyxml2::XMLElement* p_profile = p_root->FirstChildElement();
    const char* tag = nullptr;
    bool parseOk = true;
    XMLP_ret ret = XMLP_ret::XML_OK;
    while (nullptr != p_profile) {
        if (nullptr != (tag = p_profile->Value())) {
            if (strcmp(tag, xmlString::PARTICIPANT) == 0 || strcmp(tag, xmlString::PUBLISHER) == 0 ||
                strcmp(tag, xmlString::DATA_WRITER) == 0 || strcmp(tag, xmlString::SUBSCRIBER) == 0 ||
                strcmp(tag, xmlString::DATA_READER) == 0 || strcmp(tag, xmlString::TOPIC) == 0 ||
                strcmp(tag, xmlString::BASE_NAME) == 0) {
                p_profile = p_profile->NextSiblingElement();
                continue;  // this part execute in xmlparser
            }
            if (strcmp(tag, xmlString::TRANSPORT_DESCRIPTORS) == 0) {
                parseOk &= parseXMLTransportsProf(p_profile) == XMLP_ret::XML_OK;
            } else if (strcmp(tag, xmlString::LIBRARY_SETTINGS) == 0) {
                parseOk &= parseXMLLibrarySettings(p_profile) == XMLP_ret::XML_OK;
            } else if (strcmp(tag, xmlString::TYPES) == 0) {
                parseOk &= parseXMLTypes(p_profile) == XMLP_ret::XML_OK;
            } else {
                parseOk = false;
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not expected tag: '" << tag << "'");
            }
        }
        if (!parseOk) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing profile's tag ");
            ret = XMLP_ret::XML_ERROR;
        }
        p_profile = p_profile->NextSiblingElement();
    }

    return ret;
}

XMLP_ret XMLParser::parseAgentConfig(tinyxml2::XMLElement* p_root) {
    tinyxml2::XMLElement* p_profile = p_root->FirstChildElement();
    const char* tag = nullptr;
    XMLP_ret ret = XMLP_ret::XML_OK;
    while (nullptr != p_profile) {
        if (nullptr != (tag = p_profile->Value())) {
            if (strcmp(tag, xmlString::ALLOWED_TOPIC) == 0) {
                std::stringstream ss(p_profile->GetText());
                std::string topicName;
                while (std::getline(ss, topicName, '|')) {
                    std::lock_guard<std::mutex> lock(mutex_);
                    agent_allowed_topic_.emplace(topicName);
                }
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not expected tag: '" << tag << "' in agent'config.");
                ret = XMLP_ret::XML_ERROR;
            }
        }
        p_profile = p_profile->NextSiblingElement();
    }

    return ret;
}

XMLP_ret XMLParser::parseLogConfig(tinyxml2::XMLElement* p_root) {
    using vbsutil::elog::Log;

    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_aux0 = p_root->FirstChildElement(xmlString::LOG);
    if (p_aux0 == nullptr) {
        p_aux0 = p_root;
    }

    tinyxml2::XMLElement* p_element = p_aux0->FirstChildElement();
    const char* tag = nullptr;
    while (nullptr != p_element) {
        if (nullptr != (tag = p_element->Value())) {
            if (strcmp(tag, xmlString::CONSUMER) == 0) {
                ret = parseXMLConsumer(*p_element);
                if (ret == XMLP_ret::XML_ERROR) {
                    return ret;
                }
            }
        }
        p_element = p_element->NextSiblingElement();
    }
    return ret;
}

XMLP_ret XMLParser::parseXMLConsumer(tinyxml2::XMLElement& consumer) {
    using vbsutil::elog::FileConsumer;
    using vbsutil::elog::Log;
    using vbsutil::elog::LogConsumer;
    using vbsutil::elog::StdoutConsumer;
    using vbsutil::elog::StdoutErrConsumer;

    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_element = consumer.FirstChildElement(xmlString::CLASS);

    if (p_element != nullptr) {
        std::string classStr = p_element->GetText();
#if 0
#ifndef UNITEST_STATISTICS
        if (std::strcmp(classStr.c_str(), "OnlineConsumer") == 0) {
            uint32_t log_doamin            = evbs::edds::dds::OnlineConsumer::sc_DomainID;
            tinyxml2::XMLElement* property = consumer.FirstChildElement(xmlString::PROPERTY);
            if (nullptr == property) {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "domainID value is not found, please specify it.");
                ret = XMLP_ret::XML_NOK;
            } else {
                tinyxml2::XMLElement* p_auxName  = nullptr;
                tinyxml2::XMLElement* p_auxValue = nullptr;
                while (nullptr != property) {
                    // name - stringType
                    if (nullptr != (p_auxName = property->FirstChildElement(xmlString::NAME))) {
                        std::string s = p_auxName->GetText();
                        if (std::strcmp(s.c_str(), "domainID") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                uint8_t ident = 1;
                                if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLUint(p_auxValue, &log_doamin, ident)) {
                                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "domainID value is not uint32_t type, so we use default value "
                                                            << evbs::edds::dds::OnlineConsumer::sc_DomainID
                                                            << " instead.");
                                    log_doamin = evbs::edds::dds::OnlineConsumer::sc_DomainID;
                                }
                            }
#if 0  //CHILEI TODO
                            evbs::edds::dds::OnlineLogPublisher* onlinePub = new evbs::edds::dds::OnlineLogPublisher(log_doamin);
                            onlinePub->init("");
                            evbs::edds::dds::OnlineConsumer* onlineCons = new evbs::edds::dds::OnlineConsumer(onlinePub);
                            Log::RegisterConsumer(std::unique_ptr<LogConsumer>(onlineCons));
#endif
                            ret = XMLP_ret::XML_OK;
                        } else {
                            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Unknown property " << s << " in " << classStr << " log consumer.");
                            ret = XMLP_ret::XML_NOK;
                        }
                        property = property->NextSiblingElement(xmlString::PROPERTY);
                    }
                }
            }
        }
#endif  // UNITEST_STATISTICS
#endif
    }
    return ret;
}

XMLP_ret XMLParser::loadXML(const std::string& filename, vbsutil::xmlparser::up_base_node_t& root) {
    if (filename.empty()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error loading XML file, filename empty");
        return XMLP_ret::XML_ERROR;
    }

    tinyxml2::XMLDocument xmlDoc;
    tinyxml2::XMLError ret = xmlDoc.LoadFile(filename.c_str());
    if (tinyxml2::XMLError::XML_SUCCESS != ret) {
        if (filename != std::string(xmlString::DEFAULT_ERTPS_PROFILES)) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "Error opening '" << filename << "' with return code:" << ret);
        }
        return XMLP_ret::XML_ERROR;
    }

    logDebug(XMLPARSER, "File '" << filename << "' opened successfully");
    return parseXML(xmlDoc, root);
}

XMLP_ret XMLParser::loadXMLProfiles(tinyxml2::XMLElement& xmlDoc, vbsutil::xmlparser::up_base_node_t& root) {
    return parseXMLProfiles(xmlDoc, root);
}

XMLP_ret XMLParser::loadXML(tinyxml2::XMLDocument& xmlDoc, vbsutil::xmlparser::up_base_node_t& root) {
    return parseXML(xmlDoc, root);
}

XMLP_ret XMLParser::loadXML(const char* data, size_t length, vbsutil::xmlparser::up_base_node_t& root) {
    tinyxml2::XMLDocument xmlDoc;
    if (tinyxml2::XMLError::XML_SUCCESS != xmlDoc.Parse(data, length)) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing XML buffer");
        return XMLP_ret::XML_ERROR;
    }
    return parseXML(xmlDoc, root);
}

}  // namespace xmlparser
}  // namespace ertps
}  // namespace evbs
